package fortunata.fswapps.vpoet;

import com.ecyrd.jspwiki.WikiContext;
import com.hp.hpl.jena.ontology.DatatypeProperty;
import com.hp.hpl.jena.ontology.Individual;
import com.hp.hpl.jena.ontology.OntClass;
import com.hp.hpl.jena.ontology.OntModel;
import com.hp.hpl.jena.query.*;
import com.hp.hpl.jena.rdf.model.Property;
import com.hp.hpl.jena.vocabulary.RDFS;
import com.hp.hpl.jena.vocabulary.XSD;
import fortunata.FortunataSWApplication;
import org.apache.log4j.Logger;

import java.security.Principal;
import java.util.GregorianCalendar;


/**
 * This is the VPOET SemWebApp.
 */
public class Vpoet extends FortunataSWApplication {

    static final public String HttpRequestParameter_EditElement = "editElem";
    static final public String HttpRequestParameter_VisualizeElement = "visualizeElem";

    static final public String listWikiPageName = "VPOETStoredData";
    static final public String editWikiPageName = "VPOETEditElem"; //To be deleted when OnListOperation were deleted
    static final public String createWikiPageName = "VPOETCreateViz";
    static final public String VisualizeWikiPageName = "VPOETVisualizeDesign";

    static final public String propNameProviderID = "providerID";
    static final public String propNameDesignID = "designID";
    static final public String propNameOntoElemID = "ontoElemID";
    static final public String propNameCSSCode = "cssCode";
    static final public String propNameHTMLCode = "htmlCode";
    static final public String propNameJSCode = "jsCode";
    static final public String propNameModificationDate = "modificationDate";
    static final public String propNameDesignType = "designType";
    static final public String propNameStyle1 = "primaryStyle";
    static final public String propNameStyle2 = "secondaryStyle";
    static final public String propNameForeColor1 = "primaryForeColor";
    static final public String propNameForeColor2 = "secondaryForeColor";
    static final public String propNameBackgColor1 = "primaryBackgColor";
    static final public String propNameBackgColor2 = "secondaryBackgColor";
    static final public String propNameUserSTD = "userSTD";
    static final public String propNameUserRVS = "userRVS";
    static final public String propNameColorBlind = "colorBlind";
    //static final public String propNameTargetUser = "targetUser";
    static final public String propNamePolicySize = "policyForSize";
    static final public String propNamePolicyResize = "policyForResize";

    static final public String pluginGenerateListString= "[{fortunata.jspwikiplugins.vpoet.TableOfDesigns}]";
    
    private static Logger log = Logger.getLogger (Vpoet.class);

    String designID, elem, providerID,
           csscode, jscode, htmlcode,
           designType,
           selStyle1, selColour1, selBack1,
           selStyle2, selColour2, selBack2,
           userSTD,  userRVS,  colorBlind,
           policySize,
           policyResize;

    public Vpoet(){
         initialize("vpoet.model.owl",
                    "vpoet.data.owl",
                    "http://nets.ii.uam.es/ontologies/vpoet/20060501",
                    "vpoet",
                    "Visualizer",
                    "VpoetOntology");
    }
    
    public void addFormData(String designID, String elem, String providerID,
                            String csscode, String jscode, String htmlcode,
                            String designType,
                            String selStyle1, String selColour1, String selBack1,
                            String selStyle2, String selColour2, String selBack2,
                            String userSTD, String userRVS, String colorBlind,
                            String policySize,
                            String policyResize){
          this.designID= designID;
          this.elem = elem;
          this.providerID = providerID;
          this.csscode = csscode;
          this.jscode = jscode;
          this.htmlcode = htmlcode;
          this.designType = designType;
          this.selStyle1 = selStyle1;
          this.selColour1 = selColour1;
          this.selBack1 = selBack1;
          this.selStyle2 = selStyle2;
          this.selColour2 = selColour2;
          this.selBack2 = selBack2;
          this.userSTD = userSTD;
          this.userRVS = userRVS;
          this.colorBlind = colorBlind;
          this.policySize = policySize;
          this.policyResize = policyResize;
    }

    /**
     * Must be implemented. It uses the information of the creator plugin (AddVisualization in this case)
     * @return The URI of a given individual. This URI must be unique for each individual.
     */
    public  String getInstanceUniqueURI (){
        return getURI() + providerID + "." + designID;
    }

    /**
     * Used by other plugins (for example, VisualizeDesign).
     * @param designID
     * @param providerID
     * @return
     */
    public  String getInstanceUniqueURI (String designID, String providerID){
        return getURI() + providerID + "." + designID;
    }
    /**
     * Mandatory method (forced by FortunataSWApplication). This method is invoked by writeSemanticData.
     * @param context
     * @param m  The OntModel that is being used. It has been initialized. You must use it just for writing the
     * individual's data. It will be published automatically.
     * @param ind1  The individual to be filled with values. It has been created and added to the model. Just fill it.
     */
    public void createIndividual(WikiContext context, OntModel m, Individual ind1){
        //Ensures that if this operation is an actualization, it is done only by the author
         Principal currentUser = context.getCurrentUser();
         String currentUserName = currentUser.getName();
         if (m.getIndividual(getInstanceUniqueURI()) != null &&
             currentUserName.equals(providerID) == false){
            // throw new PluginException("You (" + currentUserName + ") are not the creator ("+ providerID +
            //         "). I am very sorry, but you are not allowed to modify this design");
         }
         String URI = getURI();
         Property pNameDesignID =     m.getProperty(URI + Vpoet.propNameDesignID);
         Property pNameProviderID =   m.getProperty(URI + Vpoet.propNameProviderID);
         Property pNameOntoElemID =   m.getProperty(URI + Vpoet.propNameOntoElemID);
         Property pNameCSSCode =      m.getProperty(URI + Vpoet.propNameCSSCode);
         Property pNameHTMLCode =     m.getProperty(URI + Vpoet.propNameHTMLCode);
         Property pNameJSCode =       m.getProperty(URI + Vpoet.propNameJSCode);
         Property pNameCreationDate = m.getProperty(URI + Vpoet.propNameModificationDate);
         Property pNameDesignType =   m.getProperty(URI + Vpoet.propNameDesignType);
         Property pNameStyle1 =       m.getProperty(URI + Vpoet.propNameStyle1);
         Property pNameStyle2 =       m.getProperty(URI + Vpoet.propNameStyle2);
         Property pNameForeColor1 =   m.getProperty(URI + Vpoet.propNameForeColor1);
         Property pNameForeColor2 =   m.getProperty(URI + Vpoet.propNameForeColor2);
         Property pNameBackgColor1 =  m.getProperty(URI + Vpoet.propNameBackgColor1);
         Property pNameBackgColor2 =  m.getProperty(URI + Vpoet.propNameBackgColor2);
         //Property pNameTargetUser =   m.getProperty(URI + Vpoet.propNameTargetUser);
         Property pNameUserSTD =  m.getProperty(URI + Vpoet.propNameUserSTD);
         Property pNameUserRVS =   m.getProperty(URI + Vpoet.propNameUserRVS);
         Property pNameColorBlind = m.getProperty(URI + Vpoet.propNameColorBlind);
         Property pNamePolicySize = m.getProperty(URI + Vpoet.propNamePolicySize);
         Property pNamePolicyResize = m.getProperty(URI + Vpoet.propNamePolicyResize);

         ind1.setPropertyValue(pNameDesignID, m.createLiteral(designID));
         ind1.setPropertyValue(pNameProviderID, m.createLiteral(providerID));
         ind1.setPropertyValue(pNameOntoElemID, m.createLiteral(elem));
         ind1.setPropertyValue(pNameCSSCode, m.createLiteral(csscode));
         ind1.setPropertyValue(pNameHTMLCode, m.createLiteral(htmlcode));
         ind1.setPropertyValue(pNameJSCode, m.createLiteral(jscode));
         ind1.setPropertyValue(pNameCreationDate, m.createTypedLiteral(new GregorianCalendar()));
         ind1.setPropertyValue(pNameDesignType, m.createLiteral(designType));
         ind1.setPropertyValue(pNameStyle1, m.createLiteral(selStyle1));
         ind1.setPropertyValue(pNameStyle2, m.createLiteral(selStyle2));
         ind1.setPropertyValue(pNameForeColor1, m.createLiteral(selColour1));
         ind1.setPropertyValue(pNameForeColor2, m.createLiteral(selColour2));
         ind1.setPropertyValue(pNameBackgColor1, m.createLiteral(selBack1));
         ind1.setPropertyValue(pNameBackgColor2, m.createLiteral(selBack2));

         //targetUser is a multivaluated property
         //ind1.addProperty(pNameTargetUser, m.createLiteral(userSTD));
         //ind1.addProperty(pNameTargetUser, m.createLiteral(userRVS));
         //ind1.addProperty(pNameTargetUser, m.createLiteral(colorBlind));

         ind1.setPropertyValue(pNameUserSTD, m.createLiteral(userSTD));
         ind1.setPropertyValue(pNameUserRVS, m.createLiteral(userRVS));
         ind1.setPropertyValue(pNameColorBlind, m.createLiteral(colorBlind));

         ind1.setPropertyValue(pNamePolicySize, m.createLiteral(policySize));
         ind1.setPropertyValue(pNamePolicyResize, m.createLiteral(policyResize));

         //ind1.setPropertyValue(pLastCheck, m.createTypedLiteral(new GregorianCalendar()));
    }
    /**
     * Fills up the model with the class (just create it, you will fill it later in method createIndividual),
     * properties and relations. The model will be published automatically.
     * @param m  The model, the implementation details are hidden.
     */
    public void fillDataModel(OntModel m){
            String URI = getURI();
            //Creates a class
            OntClass c1ass = m.createClass(URI + getMainClassName());
            //Creates a datatypeProperty
            DatatypeProperty pDesignID = m.createDatatypeProperty(URI + propNameDesignID);
            pDesignID.setDomain(c1ass);
            pDesignID.setRange(RDFS.Literal);
            //Creates a datatypeProperty
            DatatypeProperty pProviderID = m.createDatatypeProperty(URI + propNameProviderID);
            pProviderID.setDomain(c1ass);
            pProviderID.setRange(RDFS.Literal);
            //Creates a datatypeProperty
            DatatypeProperty pOntoElemID = m.createDatatypeProperty(URI + propNameOntoElemID);
            pProviderID.setDomain(c1ass);
            pProviderID.setRange(RDFS.Literal);
            //Creates a datatypeProperty
            DatatypeProperty pCSSCode = m.createDatatypeProperty(URI + propNameCSSCode);
            pCSSCode.setDomain(c1ass);
            pCSSCode.setRange(RDFS.Literal);
            //Creates a datatypeProperty
            DatatypeProperty pHTMLCode = m.createDatatypeProperty(URI + propNameHTMLCode);
            pHTMLCode.setDomain(c1ass);
            pHTMLCode.setRange(RDFS.Literal);
            //Creates a datatypeProperty
            DatatypeProperty pJSCode = m.createDatatypeProperty(URI + propNameJSCode);
            pJSCode.setDomain(c1ass);
            pJSCode.setRange(RDFS.Literal);
            DatatypeProperty propVersionDate = m.createDatatypeProperty(URI + propNameModificationDate);
            propVersionDate.setDomain(c1ass);
            propVersionDate.setRange(XSD.dateTime);
            //Creates a datatypeProperty
            DatatypeProperty pDesignType = m.createDatatypeProperty(URI + propNameDesignType);
            pDesignType.setDomain(c1ass);
            pDesignType.setRange(RDFS.Literal);
            //Creates a datatypeProperty
            DatatypeProperty pStyle1 = m.createDatatypeProperty(URI + propNameStyle1);
            pStyle1.setDomain(c1ass);
            pStyle1.setRange(RDFS.Literal);
            //Creates a datatypeProperty
            DatatypeProperty pStyle2 = m.createDatatypeProperty(URI + propNameStyle2);
            pStyle2.setDomain(c1ass);
            pStyle2.setRange(RDFS.Literal);
            //Creates a datatypeProperty
            DatatypeProperty pForeColor1 = m.createDatatypeProperty(URI + propNameForeColor1);
            pForeColor1.setDomain(c1ass);
            pForeColor1.setRange(RDFS.Literal);
            //Creates a datatypeProperty
            DatatypeProperty pForeColor2 = m.createDatatypeProperty(URI + propNameForeColor2);
            pForeColor2.setDomain(c1ass);
            pForeColor2.setRange(RDFS.Literal);
            //Creates a datatypeProperty
            DatatypeProperty pBackgColor1 = m.createDatatypeProperty(URI + propNameBackgColor1);
            pBackgColor1.setDomain(c1ass);
            pBackgColor1.setRange(RDFS.Literal);
            //Creates a datatypeProperty
            DatatypeProperty pBackgColor2 = m.createDatatypeProperty(URI + propNameBackgColor2);
            pBackgColor2.setDomain(c1ass);
            pBackgColor2.setRange(RDFS.Literal);
            //Creates a datatypeProperty
            DatatypeProperty pUserSTD = m.createDatatypeProperty(URI + propNameUserSTD);
            pUserSTD.setDomain(c1ass);
            pUserSTD.setRange(RDFS.Literal);
            //Creates a datatypeProperty
            DatatypeProperty pUserRVS = m.createDatatypeProperty(URI + propNameUserRVS);
            pUserRVS.setDomain(c1ass);
            pUserRVS.setRange(RDFS.Literal);
            //Creates a datatypeProperty
            DatatypeProperty pColorBlind = m.createDatatypeProperty(URI + propNameColorBlind);
            pColorBlind.setDomain(c1ass);
            pColorBlind.setRange(RDFS.Literal);
            //Creates a datatypeProperty
            DatatypeProperty pPolicySize = m.createDatatypeProperty(URI + propNamePolicySize);
            pPolicySize.setDomain(c1ass);
            pPolicySize.setRange(RDFS.Literal);
            //Creates a datatypeProperty
            DatatypeProperty pPolicyResize = m.createDatatypeProperty(URI + propNamePolicyResize);
            pPolicyResize.setDomain(c1ass);
            pPolicyResize.setRange(RDFS.Literal);
            //Creates a datatypeProperty
            //DatatypeProperty propVersionDate = m.createDatatypeProperty(URI + propNameLastCheck);
            //propOntoLang.setDomain(c1ass);
            //propOntoLang.setRange(XSD.dateTime);
    }

    
    /**
     * Query the model for a design given a designType (input/output), ontoElem and a provider.
     * @param m
     * @return the URI of the design or null if there is no one available.
     * If many are available, returns the first occurence. TODO
     */
      public String queryModel(OntModel m, String ontoElemID, String providerID, String designType){

      String queryString = "PREFIX vpoet: <" + getURI() + "> \n" +
                           "SELECT ?x \n" +
                           "WHERE \n" +
                           " { ?x vpoet:" + Vpoet.propNameOntoElemID +  " \"" + ontoElemID +  "\" . \n" +
                           "   ?x vpoet:" + Vpoet.propNameProviderID +  " \"" + providerID +  "\" . \n" +
                           "   ?x vpoet:" + Vpoet.propNameDesignType +  " \"" + designType +  "\" . \n" +
                           " }";
      Query query = QueryFactory.create(queryString) ;
      QueryExecution qexec = QueryExecutionFactory.create(query, m) ;
      String res = null;
      try {
        ResultSet results = qexec.execSelect() ;
        for ( ; results.hasNext() ; ){
          QuerySolution sol = results.nextSolution() ;
          res = sol.get("x").toString();
          break;  //Take the first one... TODO
        }
      } finally {
         qexec.close() ;
      }
      return res;
    }

    /**
     * Query the model for a design given a designID and a provider. This combination designID+provider
     * should be unique in the whole VPOET model becuase this combination is the ID id the design.
     * @param m
     * @return the URI of the design or null if there is no one available.
     */
     public String queryModelForConcreteDesign(OntModel m, String providerID, String designID){
      String queryString = "PREFIX vpoet: <" + getURI() + "> \n" +
                           "SELECT ?x \n" +
                           "WHERE \n" +
                           " { ?x vpoet:" + Vpoet.propNameProviderID +  " \"" + providerID   +  "\" . \n" +
                           "   ?x vpoet:" + Vpoet.propNameDesignID +    " \"" + designID  +  "\" . \n" +
                           " }";
      Query query = QueryFactory.create(queryString) ;
      QueryExecution qexec = QueryExecutionFactory.create(query, m) ;
      String res = null;
      try {
        ResultSet results = qexec.execSelect() ;
        for ( ; results.hasNext() ; ){
          QuerySolution sol = results.nextSolution() ;
          res = sol.get("x").toString();
          break;  //Take the first one... should be unique
        }
      } finally {
         qexec.close() ;
      }
      return res;
    }

}
